﻿using System;
using System.Collections.Generic;
using System.Linq;
using Socium.Domain.Collections;

namespace Socium.Domain.Documents {
	[Serializable]
	public class Sociogram {
		public string Name { get; set; }

		readonly ICollection<Node> _nodes = new LinkedList<Node>();

		public ICollection<Node> Nodes {
			get { return _nodes; }
		}

		#region Relations

		class NodesRegistry {
			readonly IDictionary<Person, Node> _dictionary = new Dictionary<Person, Node>();

			public NodesRegistry(IEnumerable<Node> nodes) {
				_dictionary.AddRange(nodes.MapLazy(node => node.MakePair(node.Person)));
			}

			public Node this[Person person] {
				get {
					Node result;
					return _dictionary.TryGetValue(person, out result) ? result : null;
				}
			}
		}

		public SociogramRelation[] GetRelations(Document document) {
			var nodes = new NodesRegistry(_nodes);
			var query =
				from relation in document.Relations
				let elector = nodes[relation.From]
				where elector != null
				let elected = nodes[relation.To]
				where elected != null
				select new SociogramRelation(relation, elector, elected);

			return query.ToArray();
		}

		#endregion

		public Counter GetCounter(Document document, Node node, RelationGroup relation_group) {
			var relations = document.Relations.Filter(relation => relation.RelationGroup == relation_group);

			var person = node.Person;

			var outcomings = new Set<Person>();
			outcomings.AddRange(relations.FilterLazy(relation => relation.From == person).MapLazy(relation => relation.To));

			
			var incomings = relations.Filter(relation => relation.To == person).Map(relation => relation.From);
			var mutuals = incomings.Count(outcomings.Contains);

			return new Counter(incomings.Count - mutuals, outcomings.Count - mutuals, mutuals);
		}

		public override string ToString() {
			return string.IsNullOrEmpty(Name) ? "Sociogram" : Name;
		}
	}
}